package advanced;

import javassist.*;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 字节码操作:
 * 运行时操作字节码可以让我们实现如下功能
 * 1. 动态生成新的类
 * 2. 动态改变某个类的结构(添加/删除/修改 新的属性/方法)
 * <p>
 * 优势:
 * 比反射开销小, 性能更高
 * JavaAasist性能高于反射,低于ASM
 */
public class L_JavaAssist {
    public static void main(String[] args) throws Exception {
        test2();
    }

    /**
     * 动态修改一个现有的类
     */
    public static void test2() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("advanced.Emp");//代表要创建的新类
        byte[] bytes = cc.toBytecode();
        System.out.println(Arrays.toString(bytes));//打印原始类信息


        System.out.println(cc.getName());//获取完整类名
        System.out.println(cc.getSimpleName()); //获取简要类名
        System.out.println(cc.getSuperclass());//获取父类
        System.out.println(cc.getInterfaces());//获取接口
        //修改内容
        CtMethod m = CtMethod.make("public int add(int a, int b){return a+b;}", cc);
        cc.addMethod(m);
        CtMethod m2 = new CtMethod(CtClass.intType, "add2", new CtClass[]{CtClass.intType, CtClass.intType}, cc);
        m2.setBody("{return $1+$2;}");
        cc.addMethod(m2);

        CtField f1=new CtField(CtClass.intType,"xhd",cc);
        f1.setModifiers(Modifier.PRIVATE);
        cc.addField(f1);


        //通过反射调用新生成的方法
        Class clz = cc.toClass();
        Object o = clz.newInstance();
        Method method = clz.getDeclaredMethod("add", int.class, int.class);
        method.invoke(o, 200, 300);


    }

    /**
     * 动态创建一个新的类
     *
     * @throws Exception
     */
    public void test() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.makeClass("advanced.empx");//代表要创建的新类
        CtField f1 = CtField.make("private int empno;", cc);
        CtField f2 = CtField.make("private String name;", cc);
        cc.addField(f1);
        cc.addField(f2);

        CtMethod cm1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
        CtMethod cm2 = CtMethod.make("public void  setEmpno(int empno){this.empno=empno;}", cc);
        cc.addMethod(cm1);
        cc.addMethod(cm2);

        //添加构造器
        CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc);
        constructor.setBody("{this.empno=empno;}");
        cc.writeFile("c:/myjava");//动态写出这个类
        System.out.println("生成类成功");

    }
}

class Emp {
    private String name;
    private int age;

    public Emp() {
    }

    public Emp(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}